package com.majiang.majiang.domain;

import com.majiang.majiang.service.ShuffleMaJiang;
import com.majiang.majiang.util.Check;
import com.majiang.majiang.util.PrintUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.*;
import java.util.regex.Pattern;

/**
 *
 * @author Administrator
 * 玩家
 */
@Getter
@Setter
@ToString
public class Player {
    /**
     * 玩家姓名
     */
    private String name;
    /**
     * 每个玩家的牌都放在playerMaJiangs中，容器
     */
    private List<MaJiang> playerMaJiangs = new ArrayList<>();
    /**
     * 用来指示“每个玩家的牌”在playerMaJiangs中的下标
     */
    private int playerMaJiangsIndex = 0;

    //吃碰后的牌
    private List<MaJiang> chipengMaJiangs = new ArrayList<>();

    //叫胡后要胡的牌
    private List<MaJiang> huMajiangs = new ArrayList<>();

    //当前摸到的牌
    private MaJiang currentMaJiang = null;

    //是否听牌
    private boolean ting = false;

    //判断电脑如何出牌，不能出的放在这里，和手里的所有牌取差集，就是可以出的牌
    private List<MaJiang> aiUseMaJiang = new ArrayList<>();

    private List<MaJiang> aiFeiPai = new ArrayList<>();

    public Player(String name){
        this.name = name;
    }

    /**
     * 起牌:从ShuffleMaJiang中的maJiangs中取一粒麻将，放入到自己的playerMaJiangs中
     * @param index “从ShuffleMaJiang中的maJiangs”获取麻将的指定的位置
     */
    public void gainMaJiang(ShuffleMaJiang shuffleMaJiang, int index){
        //从ShuffleMaJiang中的maJiangs中取一粒麻将，放入到自己的playerMaJiangs中
        if(shuffleMaJiang.getMaJiangs().size() > 0){
            MaJiang maJiang = shuffleMaJiang.getMaJiangs().get(index);
            maJiang.setPlayer(this);
            currentMaJiang = maJiang;
            playerMaJiangs.add(maJiang);
            playerMaJiangsIndex++;
            //原来的ShuffleMaJiang的maJiangs中的牌减少这一粒
            shuffleMaJiang.getMaJiangs().remove(index);
            this.sort();
        }else{
            shuffleMaJiang.isEnd();
        }
    }

    /**
     * 打牌：从自己的playerMaJiangs中取一粒牌，放入到ShuffleMaJiang中的river中
     */
    private void discardMaJiang(ShuffleMaJiang shuffleMaJiang, int index){
        if ((index > playerMaJiangs.size()) || (index < 0)) {
            index = 0;
        }
        //从自己的playerMaJiangs中取一粒牌，放入到ShuffleMaJiang中的river中
        shuffleMaJiang.setRiverIndex(shuffleMaJiang.getRiverIndex() + 1);
        MaJiang maJiang = playerMaJiangs.get(index);
        shuffleMaJiang.getRiver().add(maJiang);
        //自己的playerMaJiangs中减少这一粒牌
        playerMaJiangs.remove(index);
    }

    /**
     * 打牌：从自己的playerMaJiangs中取一粒牌，放入到ShuffleMaJiang中的river中
     */
    private MaJiang discardMaJiang(ShuffleMaJiang shuffleMaJiang, MaJiang maJiang){
        //从自己的playerMaJiangs中取一粒牌，放入到ShuffleMaJiang中的river中
        shuffleMaJiang.setRiverIndex(shuffleMaJiang.getRiverIndex() + 1);
        shuffleMaJiang.getRiver().add(maJiang);
        //自己的playerMaJiangs中减少这一粒牌
        playerMaJiangs.remove(maJiang);
        return maJiang;
    }

    /**
     * 输出该玩家拥有的牌
     */
    public void printMaJiangs(){
        System.out.print("【");
        for (MaJiang maJiang : playerMaJiangs) {
            PrintUtil.printMaJiang(maJiang);
        }
        System.out.print("】,");
        System.out.print("【");
        for(MaJiang maJiang: chipengMaJiangs){
            PrintUtil.printMaJiang(maJiang);
        }
        System.out.print("】");
    }

    /**
     * 按照顺序排牌
     */
    public void sort() {
        List<MaJiangNumber> w = new ArrayList<>();
        List<MaJiangNumber> s = new ArrayList<>();
        List<MaJiangNumber> t = new ArrayList<>();
        List<MaJiang> dong = new ArrayList<>();
        List<MaJiang> nan = new ArrayList<>();
        List<MaJiang> xi = new ArrayList<>();
        List<MaJiang> bei = new ArrayList<>();
        List<MaJiang> zhong = new ArrayList<>();
        List<MaJiang> fa = new ArrayList<>();
        List<MaJiang> bai = new ArrayList<>();

        for(MaJiang maJiang: this.playerMaJiangs){
            if(maJiang.getType() == 1){
                w.add((MaJiangNumber)maJiang);
            }else if(maJiang.getType() == 2){
                s.add((MaJiangNumber)maJiang);
            }else if(maJiang.getType() == 3){
                t.add((MaJiangNumber)maJiang);
            }else if(maJiang.getType() == 4){
                dong.add(maJiang);
            }else if(maJiang.getType() == 5){
                nan.add(maJiang);
            }else if(maJiang.getType() == 6){
                xi.add(maJiang);
            }else if(maJiang.getType() == 7){
                bei.add(maJiang);
            }else if(maJiang.getType() == 8){
                zhong.add(maJiang);
            }else if(maJiang.getType() == 9){
                fa.add(maJiang);
            }else{
                bai.add(maJiang);
            }
        }
        Collections.sort(w);
        Collections.sort(s);
        Collections.sort(t);

        playerMaJiangs = new ArrayList<>();
        playerMaJiangs.addAll(w);
        playerMaJiangs.addAll(s);
        playerMaJiangs.addAll(t);
        playerMaJiangs.addAll(dong);
        playerMaJiangs.addAll(nan);
        playerMaJiangs.addAll(xi);
        playerMaJiangs.addAll(bei);
        playerMaJiangs.addAll(zhong);
        playerMaJiangs.addAll(fa);
        playerMaJiangs.addAll(bai);
    }

    public boolean isTouchCards(ShuffleMaJiang shuffleMaJiang){
        //获取河里刚打出的牌
        if(shuffleMaJiang.getRiver().size() > 0){
            MaJiang riverLastJiang = shuffleMaJiang.getRiver().get(shuffleMaJiang.getRiver().size() - 1);
            //遍历自己的所有的牌，是否包含上面的牌，并且有两张
            int frequency = Collections.frequency(playerMaJiangs, riverLastJiang);
            return frequency >= 2 && riverLastJiang.getPlayer() != this;
        }
        return false;
    }

    /**
     * 碰牌:河里刚打出的牌，在玩家手中有两张同样的牌，就可以碰牌
     */
    public void touchCards(ShuffleMaJiang shuffleMaJiang){
        //获取河里刚打出的牌
        MaJiang riverLastJiang = shuffleMaJiang.getRiver().get(shuffleMaJiang.getRiver().size() - 1);
        System.out.println("【" + this.getName() + "碰牌成功】");
        //把碰的牌移除
        playerMaJiangs.remove(riverLastJiang);
        playerMaJiangs.remove(riverLastJiang);
        chipengMaJiangs.add(riverLastJiang);
        chipengMaJiangs.add(riverLastJiang);
        chipengMaJiangs.add(riverLastJiang);
        shuffleMaJiang.getRiver().remove(shuffleMaJiang.getRiver().size() - 1);
    }

    /**
     * //杠 4张一样的牌叫杠 又分明杠和暗杠，明杠需要借助别人的一张牌，暗账全部是自己摸的
     */
    public boolean isMingBarCards(ShuffleMaJiang shuffleMaJiang){
        //明杠 有两种模式，一种是碰完又抓到一张（2+1），一种是直接杠别人三张（3）
        //获取河里刚打出的牌 明杠
        if(shuffleMaJiang.getRiver().size() > 0){
            MaJiang riverLastJiang = shuffleMaJiang.getRiver().get(shuffleMaJiang.getRiver().size() - 1);
            //遍历自己的所有的牌，是否包含上面的牌，并且有三张
            int frequency = Collections.frequency(playerMaJiangs, riverLastJiang);
            //遍历自己的所有的吃碰牌，是否包含参数里的牌，并且有三张
            int frequencyChipeng = Collections.frequency(chipengMaJiangs, currentMaJiang);
            return frequencyChipeng == 3 || (frequency == 3 && riverLastJiang.getPlayer() != this);
        }
        return false;
    }

    private boolean isAnBarCards(){
        //是否有暗杠 自己抓了4张一样的牌
        for(MaJiang selfMaJiang: playerMaJiangs){
            int frequency = Collections.frequency(playerMaJiangs, selfMaJiang);
            if(frequency == 4){
                return true;
            }
        }
        return false;
    }

    /**
     * 杠牌:河里刚打出的牌，在玩家手中有3张同样的牌，就可以杠牌
     */
    public void mingBarCards(ShuffleMaJiang shuffleMaJiang){
        //获取河里刚打出的牌
        MaJiang riverLastJiang = shuffleMaJiang.getRiver().get(shuffleMaJiang.getRiver().size() - 1);
        if(chipengMaJiangs.contains(riverLastJiang)){
            shuffleMaJiang.getRiver().remove(shuffleMaJiang.getRiver().size() - 1);
            chipengMaJiangs.add(riverLastJiang);
            playerMaJiangs.remove(riverLastJiang);
        }else{
            //把杠的牌移除
            playerMaJiangs.remove(riverLastJiang);
            playerMaJiangs.remove(riverLastJiang);
            playerMaJiangs.remove(riverLastJiang);
            chipengMaJiangs.add(riverLastJiang);
            chipengMaJiangs.add(riverLastJiang);
            chipengMaJiangs.add(riverLastJiang);
            chipengMaJiangs.add(riverLastJiang);
        }
        System.out.println("【" + this.getName() + "杠牌成功】");
        //海底捞
        gainMaJiang(shuffleMaJiang, shuffleMaJiang.getMaJiangs().size() - 1);
    }

    private void anBarCards(ShuffleMaJiang shuffleMaJiang){
        for(MaJiang maJiang: playerMaJiangs){
            int frequency = Collections.frequency(playerMaJiangs, maJiang);
            if(frequency == 4){
                System.out.println("【" + this.getName() + "暗杠成功】");
                playerMaJiangs.remove(maJiang);
                playerMaJiangs.remove(maJiang);
                playerMaJiangs.remove(maJiang);
                playerMaJiangs.remove(maJiang);
                chipengMaJiangs.add(maJiang);
                chipengMaJiangs.add(maJiang);
                chipengMaJiangs.add(maJiang);
                chipengMaJiangs.add(maJiang);
                gainMaJiang(shuffleMaJiang, shuffleMaJiang.getMaJiangs().size() - 1);
            }
        }
    }

    public void isJiaoHuCard(ShuffleMaJiang shuffleMaJiang){
        List<Integer> paiList = new ArrayList<>();
        for(MaJiang maJiang: this.playerMaJiangs){
            paiList.add(maJiang.getCode());
        }
        for (Integer code: shuffleMaJiang.getType()) {
            Check.paiStack.clear();
            if (Check.check(paiList, code)) {// 和了
                int size = Check.paiStack.size();
                while(size-- > 0){
                    Check.paiStack.pop();
                }
                MaJiang maJiang = shuffleMaJiang.getPaiName(code);
                huMajiangs.add(maJiang);
                System.out.print("听牌:" + maJiang + ",");// 那么这副牌听这个牌
                ting = true;
            }
        }
    }

    /**
     * 胡牌：满足胡牌的规则
     */
    public boolean huCards(){
        //难度较大，以后再研究
        return huMajiangs.contains(currentMaJiang);
    }

//    public boolean chiHuCards(ShuffleMaJiang shuffleMaJiang) {
//        MaJiang riverLastJiang = shuffleMaJiang.getRiver().get(shuffleMaJiang.getRiver().size() - 1);
//        return huMajiangs.contains(riverLastJiang);
//    }

    //天胡
    public boolean tianHuCards() {
        List<Integer> paiList = new ArrayList<>();
        for(int i = 0; i < 13; i++){
            MaJiang maJiang = this.playerMaJiangs.get(i);
            paiList.add(maJiang.getCode());
        }
        currentMaJiang = this.playerMaJiangs.get(this.playerMaJiangs.size() - 1);
        Check.paiStack.clear();
        return Check.check(paiList, currentMaJiang.getType());// 和了
    }

    public void chupai(Scanner scanner, ShuffleMaJiang shuffleMaJiang) {
        if(!isTing(shuffleMaJiang)){
            //判断是否有暗（明）杠 如果有暗（明）杠，提示需要加入暗（明）杠，没有不提示
            if(isAnBarCards()){
                System.out.println("【您是庄家，请打一张牌。请输入:[待打出牌对应的顺序，例如：1表示打出第一张牌]，[0:暗杠]，[非数字输入:退出游戏]】");
            }else{
                System.out.println("【您是庄家，请打一张牌。请输入:[待打出牌对应的顺序，例如：1表示打出第一张牌]，[非数字输入:退出游戏]】");
            }
            String inputdiscardBoard = scanner.nextLine();
            Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
            if(inputdiscardBoard.equals("0")){
                this.anBarCards(shuffleMaJiang);
                chupai(scanner, shuffleMaJiang);
            }
            if (pattern.matcher(inputdiscardBoard).matches()) {
                //打一张牌
                this.discardMaJiang(shuffleMaJiang, Integer.valueOf(inputdiscardBoard) - 1);
                //输出此时玩家双手中的牌
                System.out.println("【此时玩家手中的牌：】");
                this.printMaJiangs();
            }else {
                System.out.println("【游戏结束，再见！】");
                System.exit(0);
            }
        }
    }

    public String aiChupai(ShuffleMaJiang shuffleMaJiang) {
        if(!isTing(shuffleMaJiang)){
            //电脑ai
            List<MaJiang> tmpList = new ArrayList<>();
            tmpList.addAll(this.playerMaJiangs);
            this.aiUseMaJiang = new ArrayList<>();
            //处理对（两个一样的）和刻（三个一样的）
            for(MaJiang maJiang: tmpList){
                int frequency = Collections.frequency(playerMaJiangs, maJiang);
                if(frequency > 1){
                    aiUseMaJiang.add(maJiang);
                }
            }
            tmpList.removeAll(aiUseMaJiang);
            MaJiang maJiang = tmpList.get(tmpList.size() - 1);
            if(maJiang.getCode() > 39){
                //没有对刻，先打风
                return discardMaJiang(shuffleMaJiang, maJiang).toString();
            }else{
                //没有对刻，没有风，处理顺子
                processShunzi(tmpList);
                Random r = new Random();
                return discardMaJiang(shuffleMaJiang, aiFeiPai.get(r.nextInt(aiFeiPai.size() - 1))).toString();
            }
        }
        return null;
    }

    private void processShunzi(List<MaJiang> tmpList){
        if(tmpList != null && !tmpList.isEmpty()){
            if(tmpList.size() <= 1){
                return;
            }
            //从后往前判断是否有顺子牌
            int i = tmpList.size() - 1;
            if(tmpList.size() > 2 && tmpList.get(i).getCode() - tmpList.get(i - 1).getCode() == 1){
                if(tmpList.size() > 3 && tmpList.get(i - 1).getCode() - tmpList.get(i - 2).getCode() == 1){
                    aiUseMaJiang.add(tmpList.get(i));
                    aiUseMaJiang.add(tmpList.get(i - 1));
                    aiUseMaJiang.add(tmpList.get(i - 2));
                    tmpList.remove(i);
                    tmpList.remove(i - 1);
                    tmpList.remove(i - 2);
                }else{
                    aiUseMaJiang.add(tmpList.get(i));
                    aiUseMaJiang.add(tmpList.get(i - 1));
                    tmpList.remove(i);
                    tmpList.remove(i - 1);
                }
                processShunzi(tmpList);
            }else{
                if(tmpList.size() > 0){
                    aiFeiPai.add(tmpList.remove(tmpList.size() - 1));
                    processShunzi(tmpList);
                }
            }
        }
    }

    private boolean isTing(ShuffleMaJiang shuffleMaJiang){
        if(ting){
            if(huCards()){
                System.out.println("【胡】");
                shuffleMaJiang.isEnd();
            }else{
                playCurrent(shuffleMaJiang);
            }
        }
        return ting;
    }

    private void playCurrent(ShuffleMaJiang shuffleMaJiang){
        //从自己的playerMaJiangs中取一粒牌，放入到ShuffleMaJiang中的river中
        shuffleMaJiang.setRiverIndex(shuffleMaJiang.getRiverIndex() + 1);
        shuffleMaJiang.getRiver().add(currentMaJiang);
        //自己的playerMaJiangs中减少这一粒牌
        playerMaJiangs.remove(currentMaJiang);
    }
}
